﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Security;
using System.Text;
using DevelopersTestPad.AppFrame;
using Ooaavee.Support;

namespace DevelopersTestPad.Worksheets
{
    internal static class WorksheetManager
    {   
        /// <summary>
        /// Gets the default worksheet type.
        /// </summary>
        public static WorksheetType DefaultWorksheetType { get { return WorksheetType.CSharpScript; }}

        /// <summary>
        /// Creates a new <see cref="Worksheet"/> for the specified <see cref="WorksheetType"/>.
        /// </summary>
        /// <param name="type">WorksheetType</param>
        /// <returns>Worksheet</returns>
        public static Worksheet CreateWorksheet(WorksheetType type)
        {
            var worksheet = new Worksheet();

            worksheet.Id = Guid.NewGuid();
            worksheet.Type = type;
            worksheet.Location = GetNewWorksheetLocation();
            worksheet.Existing = false;
            worksheet.Status = WorksheetStatus.Initialized;
            worksheet.TextData = null;

            return worksheet;
        }

        /// <summary>
        /// Tries to save a worksheet.
        /// </summary>
        /// <param name="worksheet">The worksheet to save.</param>
        /// <param name="fileName">The filename.</param>
        /// <param name="message">A possible error message.</param>
        /// <returns>true if succeed, otherwise false.</returns>
        public static bool TrySave(Worksheet worksheet, string fileName, out string message)
        {
            message = null;

            var contents = Serializer.SerializeDataContract<Worksheet>(worksheet);

            var succeed = false;

            try
            {
                File.WriteAllText(fileName, contents, Encoding.Unicode);

                succeed = true;
            }
            catch (ArgumentNullException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (PathTooLongException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (DirectoryNotFoundException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (IOException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (NotSupportedException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (SecurityException ex)
            {
                message = GetErrorMessage(ex);
            }

            if (succeed)
            {
                worksheet.Location = new FileInfo(fileName);
                worksheet.Existing = true;
                worksheet.Status = WorksheetStatus.Clean;

                AppContext.Current.OnAppNotificationReceived(new AppNotificationEventArgs { Type = AppNotificationType.WorksheetStatusChanged });
            }

            return succeed;
        }

        /// <summary>
        /// Tries to open a worksheet.
        /// </summary>
        /// <param name="fileName">The filename.</param>
        /// <param name="worksheet">The opened worksheet.</param>
        /// <param name="message">A possible error message.</param>
        /// <returns>true if succeed, otherwise false.</returns>
        public static bool TryOpen(string fileName, out Worksheet worksheet, out string message)
        {
            worksheet = null;
            message = null;

            string contents = null;

            var succeed = false;

            try
            {
                contents = File.ReadAllText(fileName, Encoding.Unicode);
                succeed = true;
            }
            catch (ArgumentException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (PathTooLongException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (DirectoryNotFoundException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (FileNotFoundException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (IOException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (NotSupportedException ex)
            {
                message = GetErrorMessage(ex);
            }
            catch (SecurityException ex)
            {
                message = GetErrorMessage(ex);
            }

            if (succeed)
            {
                succeed = false;
                try
                {
                    worksheet = Serializer.DeserializeDataContract<Worksheet>(contents);
                    succeed = true;
                }
                catch (SerializationException ex)
                {
                    message = GetErrorMessage(ex);                    
                }
            }

            if (succeed)
            {
                worksheet.Location = new FileInfo(fileName);
                worksheet.Existing = true;
                worksheet.Status = WorksheetStatus.Clean;
            }

            return succeed;
        }

        /// <summary>
        /// Gets the preferred location for a new worksheet.
        /// </summary>
        /// <returns>The preferred location for a new worksheet.</returns>
        private static FileInfo GetNewWorksheetLocation()
        {
            const string file = "Untitled.dtp";

            var currentDirectory = Directory.GetCurrentDirectory();
            if (currentDirectory.EndsWith(@"\") == false)
            {
                currentDirectory = currentDirectory + @"\";
            }

            string fileName = currentDirectory + file;

            return new FileInfo(fileName);
        }

        private static string GetErrorMessage(Exception ex)
        {
            var s = new StringBuilder();
            for (var e = ex; e != null; e = e.InnerException)
            {
                s.AppendLine(e.Message);
            }
            return s.ToString();
        }
    }
}
